#ifndef parser_h__
#define parser_h__

#include <string>
#include <map>
#include "tokenizer.h"
#include <iosfwd>

namespace CCompiler
{
	class SynNode
	{
	public:
		virtual void print(std::ostream &stream, int ident = 0) = 0;
		virtual ~SynNode() {}
	};

	class SynExpression: public SynNode
	{
	public:
		~SynExpression() {}
	};

	class SynConst: public SynExpression
	{
	};

	class SynVal: public SynExpression
	{
		std::string identifier_;
	public:
		SynVal(const std::string& identifier): identifier_(identifier) {}
		void print(std::ostream &stream, int ident = 0);
	};

	class SynBinaryOp: public SynExpression
	{
		SynExpression *first_;
		SynExpression *second_;
		std::string binOp_;
	public:
		SynBinaryOp(const std::string& binOp, SynExpression *f, SynExpression *s): 
			binOp_(binOp),
			first_(f),
			second_(s) {}
		void print(std::ostream &stream, int ident = 0);
		~SynBinaryOp() { delete first_; delete second_; }
	};

	class SynUnaryOp: public SynExpression
	{
		SynExpression *first_;
		std::string unOp_;
		bool postfix_;
	public:
		SynUnaryOp(const std::string& unOp, SynExpression *f, bool postfix = false):
		  first_(f),
		  unOp_(unOp),
		  postfix_(postfix) {}
		void print(std::ostream &stream, int ident = 0);
		~SynUnaryOp() { delete first_; }
	};

	class SynInt: public SynConst
	{
		int value_;
	public:
		SynInt(int value): value_(value) {}
		void print(std::ostream &stream, int ident = 0);
	};

	class SynChar: public SynConst
	{
		char value_;
	public:
		SynChar(char value): value_(value) {}
		void print(std::ostream &stream, int ident = 0);
	};

	class SynFloat: public SynConst
	{
		float value_;
	public:
		SynFloat(float value): value_(value) {}
		void print(std::ostream &stream, int ident = 0);
	};

	class SynString: public SynConst
	{
		std::string value_;
	public:
		SynString(const std::string value): value_(value) {}
		void print(std::ostream &stream, int ident = 0);
	};

	template<int val>
	struct Int2Type
	{
		enum{ value = val, };
	};

	class BasicParser
	{
	protected:
		Tokenizer &tokenizer_;
		template<int priority>
		SynExpression *InternalParseExpression(Int2Type<priority>);
		SynExpression *InternalParseExpression(Int2Type<2>);
		virtual SynExpression *ParseIdentifier();
		//SynExpression *ParseFunctionArgs();
		//bool isDefined(Token &) { return true; } 
		//bool isFunc(Token &) { return true; }
		//bool isArray(Token &) { return true; }
		//bool isStruct(Token &) { return true; }
	public:
		BasicParser(Tokenizer &tokenizer): tokenizer_(tokenizer) {}
		SynExpression *ParseExpression();
	};

	enum TinyNameType
	{
		ntVariable,
		ntFunction,
		ntStruct,
		ntArray,
	};

	class BasicParser2: public BasicParser
	{
		//bool isDefined(Token &tk) { return tinySymbolTable.count(tk.GetText()) != 0; } 
		//bool isFunc(Token &tk) { return tinySymbolTable[tk.GetText()] == ntFunction; }
		//bool isArray(Token &tk) { return tinySymbolTable[tk.GetText()] == ntArray; }
		//bool isStruct(Token &tk) { return tinySymbolTable[tk.GetText()] == ntStruct; }
		bool skipCheck_;
//		void EnableSkipCheck() { skipCheck_ = true; }
//		void DisableSkipCheck() { skipCheck_ = true; }

		virtual SynExpression *ParseIdentifier();
		std::map<std::string, TinyNameType> tinySymbolTable;
	public:
		BasicParser2(Tokenizer &tokenizer): BasicParser(tokenizer), skipCheck_(false) {}
		SynExpression *ParseExpression2();
	};

}

#endif // parser_h__